import { Injectable } from '@nestjs/common';
import { Request } from 'express';
import IpUtils from 'src/common/IpUtils';
import { PrismaService } from 'src/common/prisma/PrismaService';
import { Util } from 'src/common/Util';
import { UAParser } from 'ua-parser-js';
import LogininforQueryParam from '../param/LogininforQueryParam';
import SysLogininforDto from '../dto/SysLogininforDto';
import PageResult from 'src/common/PageResult';
import { plainToInstance } from 'class-transformer';
import SysOperLogQueryParam from '../param/SysOperLogQueryParam';
import SysOperLogDto from '../dto/SysOperLogDto';
import DictUtil from 'src/common/DictUtil';
import { CacheUtil } from 'src/common/CacheUtil';
import { CacheKey } from 'src/common/CacheKey';
/*
 * @Author: jingfuu@163.com
 * @Date: 2024-12-04 13:34:04
 * @LastEditTime: 2024-12-06 13:01:12
 * @Description: 系统操作日志
 */
@Injectable()
class LoggerService {
  constructor(private prisma: PrismaService) {}

  async loginUserUnlock(username: string) {
    await CacheUtil.delCache(CacheKey.USER_ACCOUNT_LOCK + username);
  }
  async logRequest(data: SysOperLogDto) {
    await this.prisma.sysOperLog.create({
      data: {
        title: data.title,
        businessType: data.businessType,
        jsonResult: data.jsonResult,
        requestMethod: data.requestMethod,
        method: data.method,
        operIp: data.operIp,
        operName: data.operName,
        operParam: data.operParam,
        operTime: data.operTime,
        operUrl: data.operUrl,
        deptName: data.deptName,
        costTime: data.costTime,
      },
    });
  }

  /**
   * 记录登录或退出日志
   * @param username 用户名
   * @param req 请求对象
   * @param status 状态
   * @param msg 日志信息
   */
  async loginInfoAdd(
    username: string,
    req: Request,
    status: string,
    msg: string,
  ) {
    const userAgent = req.headers['user-agent'];
    const parser = new UAParser(userAgent);
    const result = parser.getResult();
    await this.prisma.sysLogininfor.create({
      data: {
        browser: result.browser.name,
        ipaddr: IpUtils.getIpAddr(req),
        loginLocation: '',
        loginTime: Util.getCurrentLocalTime(),
        msg: msg,
        os: result.os.name,
        status: status,
        userName: username,
      },
    });
  }

  async listLogininfor(
    param: LogininforQueryParam,
  ): Promise<PageResult<SysLogininforDto>> {
    const skip = param.pageNum != 0 ? (param.pageNum - 1) * param.pageSize : 0;
    const whereClause: any = this.generateLogininforQueryCondition(param);
    const [total, list] = await this.prisma.$transaction([
      this.prisma.sysLogininfor.count({ where: whereClause }),
      this.prisma.sysLogininfor.findMany({
        skip,
        take: param.pageSize,
        orderBy: {
          infoId: 'desc',
        },
        where: whereClause,
      }),
    ]);
    const rows: SysLogininforDto[] = plainToInstance(SysLogininforDto, list);
    return {
      total,
      rows,
    };
  }
  generateLogininforQueryCondition(param: LogininforQueryParam): any {
    const whereClause: any = {};

    if (param.userName) {
      whereClause.userName = {
        contains: param.userName,
      };
    }

    if (param.params?.beginTime) {
      const beginTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.beginTime}`),
      );
      if (!isNaN(beginTime.getTime())) {
        // Check if the date is valid
        whereClause.loginTime = {
          ...whereClause.loginTime,
          gte: beginTime,
        };
      }
    }
    if (param.params?.endTime) {
      const endTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.endTime}`),
      );
      if (!isNaN(endTime.getTime())) {
        // Check if the date is valid
        whereClause.loginTime = {
          ...whereClause.loginTime,
          lte: endTime,
        };
      }
    }

    if (param.status !== undefined) {
      whereClause.status = param.status;
    }
    return whereClause;
  }

  async deleteLogininfor(id: number) {
    await this.prisma.sysLogininfor.delete({
      where: {
        infoId: id,
      },
    });
  }

  async cleanLogininfor() {
    await this.prisma.sysLogininfor.deleteMany();
  }

  async exportLogininfor(param: LogininforQueryParam) {
    const whereClause: any = this.generateLogininforQueryCondition(param);
    const sysLogininfor = await this.prisma.sysLogininfor.findMany({
      orderBy: {
        infoId: 'desc',
      },
      where: whereClause,
    });
    const logininforDto = plainToInstance(SysLogininforDto, sysLogininfor);
    // 设置列头
    const header = [
      { header: '访问编号', key: 'infoId', width: 10 },
      { header: '用户名称', key: 'userName', width: 20 },
      { header: '登录地址', key: 'ipaddr', width: 20 },
      { header: '浏览器', key: 'browser', width: 20 },
      { header: '操作系统', key: 'os', width: 20 },
      { header: '登录状态', key: 'status', width: 20 },
      { header: '操作信息', key: 'msg', width: 20 },
      { header: '登录日期', key: 'loginTime', width: 20 },
    ];
    const list = logininforDto.map((item) => {
      return {
        infoId: item.infoId,
        userName: item.userName,
        ipaddr: item.ipaddr,
        browser: item.browser,
        os: item.os,
        status: item.status == '0' ? '成功' : '失败',
        msg: item.msg,
        loginTime: item.loginTime,
      };
    });
    return Util.excelExport(list, header);
  }

  async listOperLog(param: SysOperLogQueryParam) {
    const skip = param.pageNum != 0 ? (param.pageNum - 1) * param.pageSize : 0;
    const whereClause: any = this.generateSysOperLogQueryCondition(param);
    const [total, list] = await this.prisma.$transaction([
      this.prisma.sysOperLog.count({ where: whereClause }),
      this.prisma.sysOperLog.findMany({
        skip,
        take: param.pageSize,
        orderBy: {
          operId: 'desc',
        },
        where: whereClause,
      }),
    ]);
    const rows: SysOperLogDto[] = plainToInstance(SysOperLogDto, list);
    return {
      total,
      rows,
    };
  }
  generateSysOperLogQueryCondition(param: SysOperLogQueryParam): any {
    const whereClause: any = {};

    if (param.title) {
      whereClause.title = {
        contains: param.title,
      };
    }

    if (param.operName) {
      whereClause.operName = {
        contains: param.operName,
      };
    }

    if (param.params?.beginTime) {
      const beginTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.beginTime}`),
      );
      if (!isNaN(beginTime.getTime())) {
        whereClause.operTime = {
          ...whereClause.operTime,
          gte: beginTime,
        };
      }
    }
    if (param.params?.endTime) {
      const endTime = Util.convertUTCToLocalTime(
        new Date(`${param.params.endTime}`),
      );
      if (!isNaN(endTime.getTime())) {
        whereClause.operTime = {
          ...whereClause.operTime,
          lte: endTime,
        };
      }
    }

    if (param.status !== undefined) {
      whereClause.status = param.status;
    }
    if (param.businessType !== undefined) {
      whereClause.businessType = param.businessType;
    }
    if (param.operIp !== undefined) {
      whereClause.operIp = param.operIp;
    }
    return whereClause;
  }

  async deleteOperlog(id: number) {
    await this.prisma.sysOperLog.delete({
      where: {
        operId: id,
      },
    });
  }

  async cleanOperlog() {
    await this.prisma.sysOperLog.deleteMany();
  }

  async exportOperlog(param: SysOperLogQueryParam) {
    const whereClause: any = this.generateSysOperLogQueryCondition(param);
    const sysOperLogs = await this.prisma.sysOperLog.findMany({
      orderBy: {
        operId: 'desc',
      },
      where: whereClause,
    });
    const sysOperLogDtos = plainToInstance(SysOperLogDto, sysOperLogs);
    // 设置列头
    const header = [
      { header: '日志编号', key: 'operId', width: 10 },
      { header: '系统模块', key: 'title', width: 20 },
      { header: '操作类型', key: 'operatorTypeLabel', width: 20 },
      { header: '操作人员', key: 'operName', width: 20 },
      { header: '操作日期', key: 'operTime', width: 20 },
    ];
    for (const item of sysOperLogDtos) {
      item.operatorTypeLabel = await DictUtil.getOperatorTypeLabel(
        item.businessType,
      );
    }
    const list = sysOperLogDtos.map((item) => {
      return {
        operId: item.operId,
        title: item.title,
        operatorTypeLabel: item.operatorTypeLabel,
        operName: item.operName,
        status: item.status == 0 ? '成功' : '失败',
        operTime: item.operTime,
      };
    });
    return Util.excelExport(list, header);
  }
}
export default LoggerService;
